home *** CD-ROM | disk | FTP | other *** search
/ APDL Other Worlds / APDL Other Worlds Collection.iso / SF3000 / Extras / CBlibrary / c / FedCompMT < prev    next >
Encoding:
Text File  |  2003-11-05  |  16.0 KB  |  597 lines

  1. /*
  2.  * CBLibrary - FedCompMT
  3.  * Copyright (C) 2003  Chris Bazley
  4.  *
  5.  * This library is free software; you can redistribute it and/or
  6.  * modify it under the terms of the GNU Lesser General Public
  7.  * License as published by the Free Software Foundation; either
  8.  * version 2.1 of the License, or (at your option) any later version.
  9.  *
  10.  * This library is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.  * Lesser General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU Lesser General Public
  16.  * License along with this library; if not, write to the Free Software
  17.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  */
  19.  
  20. /* 
  21.   Fednet-style file compression/decompression (stand alone)
  22.   Original version by David O'Shea
  23. */
  24.  
  25. /* ANSI library files */
  26. #include <stdlib.h>
  27. #include <stdio.h>
  28. #include <string.h>
  29. #include <stdbool.h>
  30. #include <limits.h>
  31.  
  32. /* RISC OS library files */
  33. #include "kernel.h"
  34. #include "flex.h"
  35.  
  36. /* Other headers */
  37. #include "msgtrans.h"
  38. #include "hourglass.h"
  39. #include "Macros.h"
  40. #include "FopenCount.h"
  41. #include "FedCompMT.h"
  42.  
  43. typedef struct _decomp_state {
  44.   FILE *f;
  45.   long int read_pos;
  46.   unsigned int len;
  47.   unsigned int dptr;
  48.   unsigned int r6;
  49. } decomp_state;
  50.  
  51. typedef struct _comp_state {
  52.   FILE *f;
  53.   unsigned int len;
  54.   unsigned int save_state;
  55.   int cptr;
  56.   int posn;
  57. } comp_state;
  58.  
  59. extern _kernel_oserror shared_err_block;
  60.  
  61. /* ----------------------------------------------------------------------- */
  62. /*                       Function prototypes                               */
  63.  
  64. static bool loadbits(decomp_state *state, unsigned int en, unsigned int *ret_r9);
  65. static unsigned int findseq(comp_state *state, char **buffer_anchor);
  66. static bool savebits(comp_state *state, unsigned int nbits, unsigned int bits);
  67.  
  68. /* ----------------------------------------------------------------------- */
  69. /*                         Public functions                                */
  70.  
  71. unsigned int get_decomp_perc(FILE ***handle)
  72. {
  73.   decomp_state *state = (decomp_state *)*handle;
  74. #ifndef NDEBUG
  75.   {
  76.     char string[255];
  77.     sprintf(string, "report get_decomp_perc state->dptr: %d len: %d", state->dptr, state->len);
  78.     _kernel_oscli(string);
  79.   }
  80. #endif
  81.   if(state->len == 0)
  82.     return 100; /* guard against divide-by-zero */
  83.  
  84.   if(state->dptr < (ULONG_MAX/100))
  85.     return (unsigned int)(state->dptr*100) / state->len;
  86.   else
  87.     return (unsigned int)(((float)state->dptr*100) / state->len);
  88. }
  89.  
  90. /* ----------------------------------------------------------------------- */
  91.  
  92. unsigned int get_comp_perc(FILE ***handle)
  93. {
  94.   comp_state *state = (comp_state *)*handle;
  95. #ifndef NDEBUG
  96.   {
  97.     char string[255];
  98.     sprintf(string, "report get_comp_perc state->cptr: %d state->len: %d", state->cptr, state->len);
  99.     _kernel_oscli(string);
  100.   }
  101. #endif
  102.  
  103.   if(state->len == 0)
  104.     return 100; /* guard against divide-by-zero */
  105.   if(state->cptr < (ULONG_MAX/100))
  106.     return (unsigned int)(state->cptr*100) / state->len;
  107.   else
  108.     return (unsigned int)(((float)state->cptr*100) / state->len);
  109. }
  110.  
  111. /* ----------------------------------------------------------------------- */
  112.  
  113. _kernel_oserror *load_compressedM(const char *filepath, flex_ptr buffer_anchor, const volatile bool *timeup, FILE ***handle)
  114. {
  115.   decomp_state *state;
  116.  
  117.   _kernel_last_oserror(); /* reset SCL's error recording */
  118.  
  119.   if(*handle == NULL) {
  120.     /* Starting afresh */
  121. #ifndef NDEBUG
  122.     _kernel_oscli("report starting decompression process");
  123. #endif
  124.  
  125.     state = (decomp_state *)malloc(sizeof(decomp_state));
  126.     if(state == NULL) {
  127.       WRITE_GERR(shared_err_block, "NoMem");
  128.       return &shared_err_block; /* fail */
  129.     }
  130.     state->dptr = 0;
  131.     state->r6 = 8;
  132.     state->f = NULL;
  133.     state->read_pos = 0;
  134.  
  135.   } else {
  136.     /* Continue from where we left off */
  137.     state = (decomp_state *)*handle;
  138. #ifndef NDEBUG
  139.     char string[255];
  140.     sprintf(string, "report continuing decompression from dptr %d", state->dptr);
  141.     _kernel_oscli(string);
  142. #endif
  143.   }
  144.  
  145.   if(state->f == NULL) {
  146.     /* (Re)open file */
  147.     state->f = fopen_inc(filepath, "rb"); /* open for reading */
  148.     if(state->f == NULL) {
  149.       free(state);
  150.       *handle = NULL; /* write back NULL pointer */
  151.       THROW(_kernel_last_oserror()) /* any OS error? */
  152.       WRITE_ERR_SUB1(shared_err_block, "OpenInFail", filepath);
  153.       return &shared_err_block; /* fail */
  154.     }
  155.     fseek(state->f, state->read_pos, SEEK_SET); /* start reading data where we left off */
  156.   }
  157.  
  158.   if(*handle == NULL) {
  159.     /* Get size of decompressed data */
  160. #ifndef NDEBUG
  161.     _kernel_oscli("report Reading size of decompressed data");
  162. #endif
  163.     if(fread(&state->len, sizeof(unsigned int), 1, state->f) != 1) {
  164.       fclose_dec(state->f);
  165.       free(state);
  166.       THROW(_kernel_last_oserror()) /* any OS error? */
  167.       WRITE_ERR_SUB1(shared_err_block, "ReadFail", filepath);
  168.       return &shared_err_block; /* fail */
  169.     }
  170.  
  171.     /* Allocate buffer for data */
  172. #ifndef NDEBUG
  173.     _kernel_oscli("report Allocating buffer for data");
  174. #endif
  175.     if(!flex_alloc(buffer_anchor, state->len)) {
  176.       fclose_dec(state->f);
  177.       free(state);
  178.       WRITE_GERR(shared_err_block, "NoMem");
  179.       return &shared_err_block; /* fail */
  180.     }
  181.   }
  182.  
  183. #ifndef NDEBUG
  184.   if(*timeup)
  185.     _kernel_oscli("report timeup before start");
  186. #endif
  187.  
  188.   do {
  189.     unsigned int r9;
  190.  
  191. //#ifndef NDEBUG
  192. //    char string[255];
  193. //    sprintf(string, "report fpos %ld", ftell(state->f));
  194. //    _kernel_oscli(string);
  195. //#endif
  196.     if(!loadbits(state, 1, &r9))
  197.       break; /* read error or EOF */
  198.     if (r9 != 1) {
  199.       unsigned int r9;
  200.       if(!loadbits(state, 8, &r9))
  201.         break; /* read error or EOF */
  202.       if(state->dptr < state->len)
  203.         ((char *)*buffer_anchor)[state->dptr] = (char)r9;
  204.       state->dptr++;
  205.     } else {
  206.       unsigned int chunk_len, read_pos;
  207.       if(!loadbits(state, 9, &read_pos))
  208.         break; /* read error or EOF */
  209.       if (read_pos >= 256) {
  210.         if(!loadbits(state, 8, &chunk_len))
  211.           break; /* read error or EOF */
  212.       } else {
  213.         if(!loadbits(state, 9, &chunk_len))
  214.           break; /* read error or EOF */
  215.       }
  216.       {
  217.         int read_offset = (state->dptr - 512) + read_pos;
  218.         unsigned int chunk_offset = 0;
  219.         char *ba = (char *)*buffer_anchor; /* careful! flex must not budge */
  220.         do {
  221.           char output_byte;
  222.           if(read_offset < 0)
  223.             output_byte = 0;
  224.           else
  225.             output_byte = ba[read_offset];
  226.           if((state->dptr + chunk_offset) < state->len)
  227.             ba[state->dptr + chunk_offset] = (char)output_byte;
  228.           else {
  229.             fclose_dec(state->f);
  230.             free(state);
  231.             *handle = NULL; /* write back NULL pointer */
  232. #ifndef NDEBUG
  233.             _kernel_oscli("report Error in compressed bitstream");
  234. #endif
  235.             WRITE_ERR(shared_err_block, "BitStream");
  236.             return &shared_err_block; /* fail */
  237.           }
  238.  
  239.           read_offset++;
  240.           chunk_offset++;
  241.         } while (chunk_offset < chunk_len);
  242.       }
  243.       state->dptr += chunk_len;
  244.     }
  245.   } while(*timeup == false);
  246.  
  247.   if(ferror(state->f)) {
  248.     /* File error on fgetc() */
  249. #ifndef NDEBUG
  250.     _kernel_oscli("report Aborting - file error on fgetc()");
  251. #endif
  252.     fclose_dec(state->f);
  253.     free(state);
  254.     *handle = NULL; /* write back NULL pointer */
  255.     THROW(_kernel_last_oserror()) /* any OS error? */
  256.     WRITE_ERR_SUB1(shared_err_block, "ReadFail", filepath);
  257.     return &shared_err_block; /* fail */
  258.   }
  259.  
  260.   if(feof(state->f)) {
  261.     /* Finished (got to end of input) */
  262. #ifndef NDEBUG
  263.     _kernel_oscli("report Decompression complete (EOF)");
  264. #endif
  265.     fclose_dec(state->f);
  266.     free(state);
  267.     *handle = NULL; /* write back NULL pointer */
  268.   } else {
  269.     /* Stopped before EOF */
  270. #ifndef NDEBUG
  271.     char string[255];
  272.     sprintf(string, "report Pausing decompression at dptr %d", state->dptr);
  273.     _kernel_oscli(string);
  274. #endif
  275.     if(fopen_num() >= FOPEN_MAX) {
  276.       /* if we have no spare file handles then close file */
  277.       state->read_pos = ftell(state->f);
  278.       fclose_dec(state->f);
  279.       state->f = NULL;
  280.     }
  281.     *handle = (FILE **)state; /* write back pointer to state */
  282.   }
  283.  
  284.   return NULL; /* no error */
  285. }
  286.  
  287. /* ----------------------------------------------------------------------- */
  288.  
  289. _kernel_oserror *save_compressedM(const char *filepath, int filetype, flex_ptr buffer_anchor, const volatile bool *timeup, FILE ***handle)
  290. {
  291.   comp_state *state;
  292.  
  293.   _kernel_last_oserror(); /* reset SCL's error recording */
  294.  
  295.   if(*handle == NULL) {
  296.     /* Starting afresh */
  297. #ifndef NDEBUG
  298.     _kernel_oscli("report starting compression process");
  299. #endif
  300.  
  301.     state = (comp_state *)malloc(sizeof(comp_state));
  302.     if(state == NULL) {
  303.       WRITE_GERR(shared_err_block, "NoMem");
  304.       return &shared_err_block; /* fail */
  305.    }
  306.     state->len = flex_size(buffer_anchor);
  307.     state->cptr = 0;
  308.     state->save_state = 0;
  309.     state->f = fopen_inc(filepath, "wb"); /* open for writing */
  310.  
  311.   } else {
  312.     /* Continue from where we left off */
  313.     state = (comp_state *)*handle;
  314. #ifndef NDEBUG
  315.     char string[255];
  316.     sprintf(string, "report continuing compression from cptr %d", state->cptr);
  317.     _kernel_oscli(string);
  318. #endif
  319.     if(state->f == NULL)
  320.       state->f = fopen_inc(filepath, "ab"); /* re-open for appending */
  321.   }
  322.  
  323.   if(state->f == NULL) {
  324.     free(state);
  325.     *handle = NULL; /* write back NULL pointer */
  326.     THROW(_kernel_last_oserror()) /* any OS error? */
  327.     WRITE_ERR_SUB1(shared_err_block, "OpenOutFail", filepath);
  328.     return &shared_err_block; /* fail */
  329.   }
  330.  
  331.   if(*handle == NULL) {
  332.     /* Write size of uncompressed data */
  333.     if(fwrite(&state->len, sizeof(unsigned int), 1, state->f) != 1)
  334.       goto err;
  335.   }
  336.  
  337. #ifndef NDEBUG
  338.   if(*timeup)
  339.     _kernel_oscli("report timeup before start");
  340. #endif
  341.  
  342.   while(state->cptr < state->len) {
  343.     char **ba = (char **)buffer_anchor;
  344.     unsigned int found;
  345. #ifndef NDEBUG
  346.     {
  347.       char string[255];
  348.       sprintf(string, "report fpos %ld", ftell(state->f));
  349.       _kernel_oscli(string);
  350.     }
  351. #endif
  352.     found = findseq(state, ba);
  353. #ifndef NDEBUG
  354.     {
  355.       char string[255];
  356.       sprintf(string, "report found:%d cptr:%d posn:%d", found, state->cptr, state->posn);
  357.       _kernel_oscli(string);
  358.     }
  359. #endif
  360.     if(found < 2) {
  361.       if(!savebits(state, 9, (*ba)[state->cptr] << 1))
  362.         goto err; /* write error */
  363.       state->cptr++;
  364.     } else {
  365.       if(!savebits(state, 10, (state->posn - state->cptr << 1) | 1))
  366.         goto err; /* write error */
  367.       if((state->posn + 256) < state->cptr) {
  368.         if(!savebits(state, 9, found))
  369.           goto err; /* write error */
  370.       } else {
  371.         if(!savebits(state, 8, found))
  372.           goto err; /* write error */
  373.       }
  374.       state->cptr += found;
  375.     }
  376.     if(*timeup == true)
  377.       break; /* out of time */
  378.   } /* endwhile */
  379.  
  380.   if(state->cptr >= state->len) {
  381.     /* Finished (got to end of input) */
  382.     if(!savebits(state, 0, 0))
  383.       goto err; /* write error */
  384. #ifndef NDEBUG
  385.     _kernel_oscli("report Compression complete");
  386. #endif
  387.     fclose_dec(state->f);
  388.     free(state);
  389.     *handle = NULL; /* write back NULL pointer */
  390.  
  391.     /* Set file type (beware of doing this before closing file!) */
  392.     {
  393.       _kernel_osfile_block inout;
  394.       inout.load = filetype;
  395.       if(_kernel_osfile(18, filepath, &inout) == _kernel_ERROR)
  396.         return _kernel_last_oserror(); /* failure */
  397.     }
  398.  
  399.   } else {
  400.     /* Assume stopped cos of time out */
  401. #ifndef NDEBUG
  402.     char string[255];
  403.     sprintf(string, "report Pausing compression at cptr %d", state->cptr);
  404.     _kernel_oscli(string);
  405. #endif
  406.     if(fopen_num() >= FOPEN_MAX) {
  407.       /* if we have no spare file handles then close file */
  408.       fclose_dec(state->f);
  409.       state->f = NULL;
  410.     }
  411.     *handle = (FILE **)state; /* write back pointer to state */
  412.   }
  413.   return NULL; /* success */
  414.  
  415. err:
  416.   /* File error on fputc() or fwrite() */
  417. #ifndef NDEBUG
  418.   _kernel_oscli("report Aborting - file error on fputc() or fwrite()");
  419. #endif
  420.   fclose_dec(state->f);
  421.   free(state);
  422.   *handle = NULL; /* write back NULL pointer */
  423.   THROW(_kernel_last_oserror()) /* any OS error? */
  424.   WRITE_ERR_SUB1(shared_err_block, "WriteFail", filepath);
  425.   return &shared_err_block; /* fail */
  426. }
  427.  
  428. /* ----------------------------------------------------------------------- */
  429. /*                         Private functions                               */
  430.  
  431. static bool loadbits(decomp_state *state, unsigned int en, unsigned int *ret_r9)
  432. {
  433.   /* Returns false to indicate read error or end of file */
  434.   unsigned int r6, r9, shifty;
  435.  
  436.   r9 = 0;
  437.   r6 = state->r6;
  438.   for (shifty = 0; shifty < en; shifty++) {
  439.     if ((r6 & 0xff) == 8) {
  440.       int r0 = fgetc(state->f);
  441.       if(r0 == EOF) {
  442.         state->r6 = r6;
  443.         return false; /* read error or EOF */
  444.       } else
  445.         r6 = r0<<8;
  446.     }
  447.     {
  448.       int r14 = (r6>>8);
  449.       r6 &= 0xff;
  450.       r6 += r14<<8;
  451.       {
  452.         int r12 = r14 & (1<<r6);
  453.         if(r12 > 0)
  454.           r12 = 1;
  455.         r9 += (r12<<shifty);
  456.       }
  457.     }
  458.     r6++;
  459.   }
  460.   state->r6 = r6;
  461.   *ret_r9 = r9;
  462.   return true; /* success */
  463. }
  464.  
  465. /* ----------------------------------------------------------------------- */
  466.  
  467. static bool savebits(comp_state *state, unsigned int nbits, unsigned int bits)
  468. {
  469.   /* Returns false to indicate write error */
  470.   unsigned int posn, output;
  471.  
  472. #ifndef NDEBUG
  473.   {
  474.     char string[255];
  475.     sprintf(string, "report savebits save_state:%X nbits:%d bits:%X", state->save_state, nbits, bits);
  476.     _kernel_oscli(string);
  477.   }
  478. #endif
  479.   posn = state->save_state & 0xff;
  480.   output = state->save_state >> 8;
  481.  
  482.   if(nbits == 0) {
  483.     if(posn > 0) {
  484. #ifndef NDEBUG
  485.       {
  486.         char string[255];
  487.         sprintf(string, "report fputc %lX:%X", ftell(state->f), output);
  488.         _kernel_oscli(string);
  489.       }
  490. #endif
  491.       if(fputc(output, state->f) == EOF)
  492.         return false; /* write error */
  493.     }
  494.     return true; /* success */
  495.   }
  496.   {
  497.     unsigned int bit;
  498.     for(bit = 0; bit < nbits; bit++) {
  499.       output = output | ((bits & 1) << posn);
  500.       bits >>= 1;
  501.       posn++;
  502.       if(posn == 8) {
  503. #ifndef NDEBUG
  504.         {
  505.           char string[255];
  506.           sprintf(string, "report fputc %lX:%X", ftell(state->f), output);
  507.           _kernel_oscli(string);
  508.         }
  509. #endif
  510.         if(fputc(output, state->f) == EOF)
  511.           return false; /* write error */
  512.         posn = output = 0;
  513.       }
  514.     }
  515.   }
  516.   state->save_state = (output << 8) | posn;
  517.   return true; /* success */
  518. }
  519.  
  520. /* ----------------------------------------------------------------------- */
  521.  
  522. static unsigned int findseq(comp_state *state, char **buffer_anchor)
  523. {
  524.   unsigned int mcount = 0;
  525.   char *ba = *buffer_anchor; /* careful! flexblock must stay put */
  526.  
  527.   if (ba[state->cptr] == 0 && ba[state->cptr+1] == 0) {
  528.     unsigned int seqptr = state->cptr;
  529.     state->posn = state->cptr - 512;
  530.     for(mcount = 0; mcount < 511; mcount++) {
  531.       if(ba[seqptr] != 0
  532.       || seqptr >= state->len
  533.       || (state->posn + (int)mcount >= 0 && ba[state->posn + mcount] != 0))
  534.         break;
  535.       seqptr++;
  536.     }
  537.   }
  538.  
  539.   {
  540.     int buff;
  541.     unsigned int max;
  542.  
  543.     if(state->cptr < 511)
  544.       buff = 0;
  545.     else
  546.       buff = state->cptr - 511;
  547.  
  548.     if(state->cptr > state->len)
  549.       max = state->len;
  550.     else
  551.       max = state->cptr;
  552.  
  553.     while(buff < max) {
  554.       int bufcompfptr;
  555.       unsigned int seqptr = state->cptr;
  556.  
  557.       for(bufcompfptr = buff; bufcompfptr < max; bufcompfptr++) {
  558.         if(ba[bufcompfptr] == ba[seqptr]
  559.         || seqptr >= state->len)
  560.           break;
  561.       }
  562.  
  563.       if(bufcompfptr >= max)
  564.         return mcount;
  565.  
  566.       {
  567.         unsigned int count, maxcount;
  568.         int start = bufcompfptr;
  569.  
  570.         if((bufcompfptr + 256) < state->cptr)
  571.           maxcount = 511;
  572.         else
  573.           maxcount = 255;
  574.  
  575.         {
  576.           unsigned int seqptr = state->cptr;
  577.           for(count = 0; count < maxcount; count++) {
  578.             if(ba[bufcompfptr] != ba[seqptr]
  579.             || bufcompfptr >= max
  580.             || seqptr >= state->len)
  581.               break;
  582.             bufcompfptr++;
  583.             seqptr++;
  584.           }
  585.         }
  586.  
  587.         if(count > mcount) {
  588.           mcount = count;
  589.           state->posn = start;
  590.         }
  591.         buff = start + 1;
  592.       }
  593.     }
  594.   }
  595.   return mcount;
  596. }
  597.